package raytracer.file;
import raytracer.file.*;
import raytracer.geometry.*;
import raytracer.geometry.Rotation.Axis;


import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import java.io.File;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Vector;
 

public class XMLImporter {
	
	private Vector<RT_Object> allObjects = new Vector<RT_Object>();
	
	private float[] lamp = new float[3];
	private float[] eye = new float[3];
	
	private boolean shadow;
	private boolean anti_aliasing;
	
	public float[] getEyeVector()
	{
		return eye;
	}
	
	public float[] getLampVector()
	{
		return lamp;
	}
	
	public Vector<RT_Object> getObjectList()
	{
		return allObjects;
	}
	
	public boolean isShadowEnabled()
	{
		return shadow;
	}
	
	public boolean anti_aliasing()
	{
		return anti_aliasing;
	}
	
	public SceneNode getSceneGraph(String filepath)
	{
		SceneNode root = new SceneNode();
		
		try {
			 
			File fXmlFile = new File(filepath);
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.parse(fXmlFile);
			doc.getDocumentElement().normalize();
	 
			
			System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
			NodeList nList = doc.getElementsByTagName("NODE");
			Node setupNode = doc.getElementsByTagName("SETUP").item(0); //getNode("SETUP", nList);
	
			 eye[0] = Float.parseFloat((getNodeAttr("x", getNode("eye", setupNode.getChildNodes()))));
			 eye[1] = Float.parseFloat((getNodeAttr("y", getNode("eye", setupNode.getChildNodes()))));
			 eye[2] = Float.parseFloat((getNodeAttr("z", getNode("eye", setupNode.getChildNodes()))));
			 
			 lamp[0] = Float.parseFloat((getNodeAttr("x", getNode("lamp", setupNode.getChildNodes()))));
			 lamp[1] = Float.parseFloat((getNodeAttr("y", getNode("lamp", setupNode.getChildNodes()))));
			 lamp[2] = Float.parseFloat((getNodeAttr("z", getNode("lamp", setupNode.getChildNodes()))));
			
			 
			 shadow = getAttributeFromChildNode("shadow", "val", setupNode);
			 anti_aliasing = getAttributeFromChildNode("anti_aliasing", "val", setupNode);
			
			return getSceneNode(getNode("NODE", nList));

		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return null;
	
	}	
	
	private boolean getAttributeFromChildNode(String childNode, String attribute, Node node)
	{
		String attr =   getNodeAttr(attribute, getNode(childNode, node.getChildNodes()));
		if (attr.toLowerCase().equals("true"))
			return true;
		else
			return false;
		
		
	}
	
		
		
	  private SceneNode getSceneNode(Node currentNode)
	  {
		  SceneNode sceneNode = new SceneNode(); 
		  NodeList childNodes = currentNode.getChildNodes();
		  
		  SceneNode root = sceneNode;
		  
		  
		  for(int i = 0; i < childNodes.getLength(); i++)
		  {
		        if (childNodes.item(i).getNodeName().equalsIgnoreCase("TRANSFORMATION")) 
		        {
					  Node transformation = childNodes.item(i);
					  if (transformation != null)
					  {
						  if(i > 0)
						  {
							  SceneNode newNode = new SceneNode();
							  sceneNode.childs.add(newNode);
							  sceneNode = newNode;
							  
						  }
							  String transLationType = getNodeAttr("type", transformation);
							  float[] centroid;
						  
							  switch(transLationType)
							  {
							  case "translation":
								  float[] translationVector = new float[3];
								  translationVector[0] = Float.parseFloat((getNodeAttr("x", getNode("vector", transformation.getChildNodes()))));
								  translationVector[1] = Float.parseFloat((getNodeAttr("y", getNode("vector", transformation.getChildNodes()))));
								  translationVector[2] = Float.parseFloat((getNodeAttr("z", getNode("vector", transformation.getChildNodes()))));
								  sceneNode.transformation = new Translation(translationVector);
								  break;
							  case "rotation":
								  centroid = new float[3];
								  centroid[0] = Float.parseFloat((getNodeAttr("x", getNode("centroid", transformation.getChildNodes()))));
								  centroid[1] = Float.parseFloat((getNodeAttr("y", getNode("centroid", transformation.getChildNodes()))));
								  centroid[2] = Float.parseFloat((getNodeAttr("z", getNode("centroid", transformation.getChildNodes()))));
								  char cAxis = getNodeAttr("x", getNode("axis", transformation.getChildNodes())).charAt(0);
								  float angle = Float.parseFloat((getNodeAttr("a", getNode("angle", transformation.getChildNodes()))));
								  Rotation.Axis axis = Axis.X_AXIS;
								  switch(cAxis)
								  {
								  	case 'x': axis = Axis.X_AXIS;
								  			break;
								  	case 'y': axis =Axis.Y_AXIS;
								  			break;
								  	default: axis = Axis.Z_AXIS;  
								  }
								  
								  sceneNode.transformation = new Rotation(angle, centroid, axis);
								  break;
							  case "scale":
								  centroid = new float[3];
								  centroid[0] = Float.parseFloat((getNodeAttr("x", getNode("centroid", transformation.getChildNodes()))));
								  centroid[1] = Float.parseFloat((getNodeAttr("y", getNode("centroid", transformation.getChildNodes()))));
								  centroid[2] = Float.parseFloat((getNodeAttr("z", getNode("centroid", transformation.getChildNodes()))));
								  float factor = Float.parseFloat((getNodeAttr("f", getNode("factor", transformation.getChildNodes()))));
								  sceneNode.transformation = new Scale(factor, centroid);
							  }
						  }
					  }
					  
		        }
		        
		  
		  
		  
		  
		  
		  
		  Node object = getNode("OBJECT", childNodes);
		  if ( object != null)
		  {
			  String objPath = getNodeValue(object);
			  RT_Object t_mesh;
			  
			  if (objPath.endsWith("dat"))
			  {
				  try 
				  {
					t_mesh = RTFileReader.read(T_Mesh.class, new File(objPath));
					sceneNode.rtObject = t_mesh;
					allObjects.add(t_mesh);
				  }
				  catch (IOException e) 
				  {
					// TODO Auto-generated catch block
					e.printStackTrace();
				  }
			  }
			  else if (objPath.endsWith("obj"))
			  {
				  try 
				  {
					  t_mesh = OBJFileReader.readFile(new File(objPath));
					  sceneNode.rtObject = t_mesh;
					  allObjects.add(t_mesh);
				  }
				  catch (Exception e) 
				  {
					// TODO Auto-generated catch block
					e.printStackTrace();
				  }	  
			  }
			  else if (objPath.endsWith("ipl"))
			  {
				  try 
				  {
					  t_mesh = RTFileReader.read(I_Plane.class, new File(objPath));
					  sceneNode.rtObject = t_mesh;
					  allObjects.add(t_mesh);
				  }
				  catch (Exception e) 
				  {
					// TODO Auto-generated catch block
					e.printStackTrace();
				  }					  
			  }
		  }
		  
		  
		  else
		  {
			  for(int x = 0; x < childNodes.getLength(); x++)
			  {
			        if (childNodes.item(x).getNodeName().equalsIgnoreCase("NODE")) 
			        {
			            SceneNode node = getSceneNode(childNodes.item(x));
			            sceneNode.childs.add(node);
			        }
				  
			  }
		  }
		  
		  return root;
	  }
	  
	  private Node getNode(String tagName, NodeList nodes) {
		    for ( int x = 0; x < nodes.getLength(); x++ ) {
		        Node node = nodes.item(x);
		        if (node.getNodeName().equalsIgnoreCase(tagName)) {
		            return node;
		        }
		    }
		 
		    return null;
		}
		
	  protected String getNodeValue( Node node ) {
		    NodeList childNodes = node.getChildNodes();
		    for (int x = 0; x < childNodes.getLength(); x++ ) {
		        Node data = childNodes.item(x);
		        if ( data.getNodeType() == Node.TEXT_NODE )
		            return data.getNodeValue();
		    }
		    return "";
		}
		

		
	
	
protected String getNodeAttr(String attrName, Node node ) {
    NamedNodeMap attrs = node.getAttributes();
    for (int y = 0; y < attrs.getLength(); y++ ) {
        Node attr = attrs.item(y);
        if (attr.getNodeName().equalsIgnoreCase(attrName)) {
            return attr.getNodeValue();
        }
    }
    return "";
}

} 
